<!DOCTYPE html>
<html lang="zh" xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title th:text="${title}">五子棋游戏</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }

        #board {
            display: grid;
            grid-template-columns: repeat(19, 30px);
            grid-template-rows: repeat(19, 30px);
            gap: 0;
            border: 2px solid #333;
            background-color: #d8b595;
        }

        .cell {
            width: 30px;
            height: 30px;
            border: 1px solid #ccc;
            box-sizing: border-box;
            position: relative;
        }

        .stone {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            position: absolute;
            top: 1px;
            left: 1px;
        }

        .black {
            background-color: #000;
        }

        .white {
            background-color: #fff;
        }

        button {
            margin: 10px;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
        }

        #status {
            margin-top: 10px;
            font-size: 18px;
        }
    </style>
</head>
<body>
<div id="board"></div>
<div>
    <button id="newGame">新游戏</button>
    <label><input type="checkbox" id="aiCheckbox"> 对战AI</label>
    <p id="status">当前玩家: 黑棋</p>
</div>

<script>
    const boardElement = document.getElementById('board');
    const newGameButton = document.getElementById('newGame');
    const aiCheckbox = document.getElementById('aiCheckbox');
    const statusText = document.getElementById('status');

    const BOARD_SIZE = 19;
    let gameBoard = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0)); // 0 表示空
    let currentPlayer = 1; // 1 表示黑棋，2 表示白棋

    //绘制棋盘
    function drawBoard() {
        boardElement.innerHTML = '';
        for (let i = 0; i < BOARD_SIZE; i++) {
            for (let j = 0; j < BOARD_SIZE; j++) {
                const cell = document.createElement('div');
                cell.classList.add('cell');
                cell.dataset.row = i;
                cell.dataset.col = j;
                cell.addEventListener('click', handleCellClick);
                boardElement.appendChild(cell);
            }
        }
    }

    //处理单元格点击事件
    function handleCellClick(event) {
        const row = parseInt(event.target.dataset.row);
        const col = parseInt(event.target.dataset.col);

        if (gameBoard[row][col] === 0) {
            gameBoard[row][col] = currentPlayer;
            const stone = document.createElement('div');
            stone.classList.add('stone', currentPlayer === 1 ? 'black' : 'white');
            event.target.appendChild(stone);

            if (checkWin(row, col, currentPlayer)) {
                statusText.textContent = `${currentPlayer === 1 ? '黑棋' : '白棋'} 获胜！`;
                disableBoard();
            } else if (isBoardFull()) {
                statusText.textContent = '平局！';
            } else {
                currentPlayer = currentPlayer === 1 ? 2 : 1;

                if (aiCheckbox.checked && currentPlayer === 2) {
                    statusText.textContent = '当前玩家: AI';
                    setTimeout(makeAIMove, 300); // 延迟让玩家看到自己的落子
                } else {
                    statusText.textContent = `当前玩家: ${currentPlayer === 1 ? '黑棋' : '白棋'}`;
                }
            }
        }
    }

    //检查指定位置是否形成五连珠。
    function checkWin(row, col, player) {
        return checkLine(row, col, player, 1, 0) ||
            checkLine(row, col, player, 0, 1) ||
            checkLine(row, col, player, 1, 1) ||
            checkLine(row, col, player, 1, -1);
    }
    //沿着指定方向检查是否有连续五个相同的棋子。
    function checkLine(row, col, player, dRow, dCol) {
        let count = 1;
        for (let i = 1; i < 5; i++) {
            if (getCellValue(row + i * dRow, col + i * dCol) !== player) break;
            count++;
        }
        for (let i = 1; i < 5; i++) {
            if (getCellValue(row - i * dRow, col - i * dCol) !== player) break;
            count++;
        }
        return count >= 5;
    }
    //获取指定位置的棋盘值，超出边界返回0。
    function getCellValue(row, col) {
        if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE) return 0;
        return gameBoard[row][col];
    }

    //检查棋盘是否已满
    function isBoardFull() {
        for (let row of gameBoard) {
            for (let cell of row) {
                if (cell === 0) return false;
            }
        }
        return true;
    }

    //开始新游戏，重置游戏状态。
    function resetGame() {
        gameBoard = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
        currentPlayer = 1;
        statusText.textContent = '当前玩家: 黑棋';
        drawBoard();
    }

    //禁用棋盘，移除所有单元格的点击事件监听器
    function disableBoard() {
        const cells = document.querySelectorAll('.cell');
        cells.forEach(cell => cell.removeEventListener('click', handleCellClick));
    }

    //实现ai对战
    function makeAIMove() {
        const bestMove = minimax(gameBoard, 2, -Infinity, Infinity, true);
        const { row, col } = bestMove.bestMove;

        gameBoard[row][col] = currentPlayer;
        const stone = document.createElement('div');
        stone.classList.add('stone', currentPlayer === 1 ? 'black' : 'white');
        document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`).appendChild(stone);

        if (checkWin(row, col, currentPlayer)) {
            statusText.textContent = `${currentPlayer === 1 ? '黑棋' : '白棋'} 获胜！`;
            disableBoard();
        } else if (isBoardFull()) {
            statusText.textContent = '平局！';
        } else {
            currentPlayer = currentPlayer === 1 ? 2 : 1;
            statusText.textContent = `当前玩家: ${currentPlayer === 1 ? '黑棋' : '白棋'}`;
        }
    }
    //ai玩家查找最优下法
    function minimax(board, depth, alpha, beta, maximizingPlayer) {
        const emptyCells = getEmptyCells(board);
        const winner = checkWinner(board);

        if (depth === 0 || emptyCells.length === 0 || winner) {
            return { score: evaluateBoard(board, winner) };
        }

        if (maximizingPlayer) {
            let maxEval = -Infinity;
            let bestMove = null;

            for (const move of emptyCells) {
                const { row, col } = move;
                board[row][col] = 2; // AI 是白棋
                const eval = minimax(board, depth - 1, alpha, beta, false).score;
                board[row][col] = 0;

                if (eval > maxEval) {
                    maxEval = eval;
                    bestMove = move;
                }

                alpha = Math.max(alpha, eval);
                if (beta <= alpha) break;
            }

            return { score: maxEval, bestMove };
        } else {
            let minEval = Infinity;
            let bestMove = null;

            for (const move of emptyCells) {
                const { row, col } = move;
                board[row][col] = 1; // 玩家是黑棋
                const eval = minimax(board, depth - 1, alpha, beta, true).score;
                board[row][col] = 0;

                if (eval < minEval) {
                    minEval = eval;
                    bestMove = move;
                }

                beta = Math.min(beta, eval);
                if (beta <= alpha) break;
            }

            return { score: minEval, bestMove };
        }
    }
    //获取所有空闲的棋盘位置。
    function getEmptyCells(board) {
        const emptyCells = [];
        for (let i = 0; i < BOARD_SIZE; i++) {
            for (let j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] === 0) {
                    emptyCells.push({ row: i, col: j });
                }
            }
        }
        return emptyCells;
    }
    //检查当前局面是否有玩家获胜。
    function checkWinner(board) {
        for (let i = 0; i < BOARD_SIZE; i++) {
            for (let j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] !== 0 && checkLine(i, j, board[i][j], 1, 0)) return board[i][j]; // 水平
                if (board[i][j] !== 0 && checkLine(i, j, board[i][j], 0, 1)) return board[i][j]; // 垂直
                if (board[i][j] !== 0 && checkLine(i, j, board[i][j], 1, 1)) return board[i][j]; // 主对角线
                if (board[i][j] !== 0 && checkLine(i, j, board[i][j], 1, -1)) return board[i][j]; // 副对角线
            }
        }
        return null;
    }

    //评估棋盘状态
    function evaluateBoard(board, winner) {
        if (winner === 2) return 100000; // AI 赢了
        if (winner === 1) return -100000; // 玩家赢了
        if (isBoardFull(board)) return 0; // 平局

        let score = 0;

        for (let i = 0; i < BOARD_SIZE; i++) {
            for (let j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] === 0) {
                    score += evaluatePosition(board, i, j, 2) - evaluatePosition(board, i, j, 1);
                }
            }
        }

        return score;
    }
    //评估特定位置的价值，考虑不同方向的连珠数量。
    function evaluatePosition(board, row, col, player) {
        let score = 0;

        // 水平方向
        score += evaluateDirection(board, row, col, player, 1, 0);
        // 垂直方向
        score += evaluateDirection(board, row, col, player, 0, 1);
        // 主对角线方向
        score += evaluateDirection(board, row, col, player, 1, 1);
        // 副对角线方向
        score += evaluateDirection(board, row, col, player, 1, -1);

        return score;
    }
    //沿着指定方向评估连珠的数量和是否被对方阻挡。
    function evaluateDirection(board, row, col, player, dRow, dCol) {
        let count = 0;
        let blockByOpponent = 0;

        for (let i = 1; i < 5; i++) {
            const r = row + i * dRow;
            const c = col + i * dCol;

            if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) break;

            if (board[r][c] === player) {
                count++;
            } else if (board[r][c] === (player === 1 ? 2 : 1)) {
                blockByOpponent++;
                break;
            } else {
                break;
            }
        }

        for (let i = 1; i < 5; i++) {
            const r = row - i * dRow;
            const c = col - i * dCol;

            if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) break;

            if (board[r][c] === player) {
                count++;
            } else if (board[r][c] === (player === 1 ? 2 : 1)) {
                blockByOpponent++;
                break;
            } else {
                break;
            }
        }

        if (count === 4 && blockByOpponent === 0) return 10000; // 连四
        if (count === 3 && blockByOpponent === 0) return 1000; // 连三
        if (count === 2 && blockByOpponent === 0) return 100; // 连二
        if (count === 1 && blockByOpponent === 0) return 10; // 连一

        return 0;
    }

    //重置游戏
    newGameButton.addEventListener('click', resetGame);
    drawBoard();
</script>
</body>
</html>